package com.bindatax.core.dspool;

import com.bindatax.core.log.LogOutInterface;
import com.bindatax.core.log.LogOutManager;
import com.bindatax.core.util.BinDataxStringUtil;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class DataTaskConnManager {

    private static Properties commPoolConfig;

    private final static Map<String,DataSource> DATA_SOURCE_MAP = new HashMap<>();
    private final static Map<String,Properties> DATABASE_CONFIG_MAP = new HashMap<>();
    private final static Map<String,ReentrantLock> LOCK_MAP = new ConcurrentHashMap<>();
    private final static LogOutInterface LOG = LogOutManager.get();
    /**
     * 由key获取连接
     * @param connKey
     * @return
     */
    public static Connection getConnection(String connKey) throws Exception{
        if(connKey == null){
            throw new Exception("connKey不能为空！");
        }
        Connection connection = null;
        DataSource dataSource = getDataSource(connKey);
        if(dataSource != null){
            connection = dataSource.getConnection();
        }
        if(connection == null){
            Properties properties = DATABASE_CONFIG_MAP.get(connKey);
            StringBuilder msg = new StringBuilder();
            if(properties == null || properties.isEmpty() ){
                msg.append("数据库连接connKey[" ).append(connKey).append("]尚未注册！");
            }else {
                Set<String> names = properties.stringPropertyNames();
                msg.append("数据库连接connKey[" ).append(connKey).append("]： ").append(LogOutManager.CR);
                for (String name : names){
                    msg.append("\t").append(name).append("=").append( properties.get(name) ).append(LogOutManager.CR);
                }
                msg.append("无法获取数据库连接！请确认连接信息是否正确！");
            }
            throw new Exception(msg.toString());
        }
        return connection;
    }

    public static Properties getDbConfig(String connKey){
        return DATABASE_CONFIG_MAP.get(connKey);
    }

    public static String buildConnection(String url ,String username, String pwd,String dataBaseDriver,String validationQuery) throws Exception{
        String connKey = getConnKey(url, username, pwd, dataBaseDriver);
        ReentrantLock db_lock = LOCK_MAP.computeIfAbsent(connKey , v -> new ReentrantLock());
        db_lock.lock();
        DataSource dataSource = getDataSource(connKey);
        try {
            if(dataSource == null){
                Properties properties = new Properties();
                properties.putAll( commPoolConfig );
                HikariConfig hikariConfig = new HikariConfig(properties);
                hikariConfig.setUsername(username);
                hikariConfig.setPassword(pwd);
                hikariConfig.setJdbcUrl(url);
                hikariConfig.setDriverClassName(dataBaseDriver);
                hikariConfig.setConnectionTestQuery( validationQuery );
                dataSource = new HikariDataSource(hikariConfig);
                DATA_SOURCE_MAP.put(connKey , dataSource);
                DATABASE_CONFIG_MAP.put(connKey,properties);
            }
        }finally {
            db_lock.unlock();
        }
        return connKey;
    }

    public static DataSource getDataSource(String connKey){
        if(connKey == null){
            return null;
        }
        return DATA_SOURCE_MAP.get(connKey);
    }

    public static void close(ResultSet res, PreparedStatement pst,Connection connection){
        if(res != null){
            try {
                res.close();;
            }catch (Exception ignored){}
        }
        if(pst != null){
            try {
                pst.close();;
            }catch (Exception ignored){}
        }
        if(connection != null){
            try {
                connection.close();;
            }catch (Exception ignored){}
        }
    }

    public static void init(Properties properties){
        commPoolConfig = properties;
    }

    /**
     * 获取连接key
     * @param url
     * @param user
     * @param pwd
     * @param dataBaseDriver
     * @return
     */
    private static String getConnKey(String url ,String user, String pwd,String dataBaseDriver){
        url = replaceNull(url,"");
        user = replaceNull(user,"");
        pwd = replaceNull(pwd,"");
        dataBaseDriver = replaceNull(dataBaseDriver,"");
        return BinDataxStringUtil.md5( url+user+pwd+dataBaseDriver );
    }

    public static <T> T replaceNull(T value , T rep){
        return value == null ? rep : value;
    }
}
